package com.ming.mallchat.common.websocket;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.ming.mallchat.common.websocket.domain.enums.WSReqTypeEnum;
import com.ming.mallchat.common.websocket.domain.service.WebSocketService;
import com.ming.mallchat.common.websocket.domain.utils.NettyUtils;
import com.ming.mallchat.common.websocket.domain.vo.req.WSBaseReq;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import io.netty.channel.ChannelHandler.Sharable;

/**
 * @author 86150
 * @date 2023/09/25
 */
@Sharable
@Slf4j
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private WebSocketService webSocketService;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        webSocketService = SpringUtil.getBean(WebSocketService.class);
        webSocketService.connect(ctx.channel());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            //从netty中获取token（达到实现握手时认证）
            String token = NettyUtils.getAttr(ctx.channel(), NettyUtils.TOKEN);
            if (StringUtils.isNotBlank(token)) {
                webSocketService.author(ctx.channel(), token);
            }
        }else if (evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                //读空闲用户下线
                userOffline(ctx);
            }
        }
    }

    /**
     * 用户统一下线
     * @param ctx
     */
    private void userOffline(ChannelHandlerContext ctx) {
        webSocketService.remove(ctx);
        ctx.channel().close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        String json = textWebSocketFrame.text();
        WSBaseReq req = JSONUtil.toBean(json, WSBaseReq.class);
        switch (WSReqTypeEnum.of(req.getType())) {
            case LOGIN:
                 webSocketService.handleLoginReq(channelHandlerContext.channel());
                break;
            case AUTHORIZE:
                webSocketService.author(channelHandlerContext.channel(),req.getData());
                break;
            case HEARTBEAT:
                break;
        }
    }
}
